package cn.factorybox.item.service.impl;

import cn.factorybox.common.entity.PageResult;
import cn.factorybox.common.utils.BeanMapUtils;
import cn.factorybox.common.utils.DateFormatUtil;
import cn.factorybox.common.utils.HttpClient;
import cn.factorybox.common.utils.resultUtils.EchartsUtils;
import cn.factorybox.common.utils.IdWorker;
import cn.factorybox.common.utils.resultUtils.ResultUtils;
import cn.factorybox.common.utils.resultUtils.WarningCountUtils;
import cn.factorybox.item.mapper.DeviceDataMapper;
import cn.factorybox.item.mapper.DeviceMapper;
import cn.factorybox.item.mapper.JudgeValueMapper;
import cn.factorybox.item.service.DeviceDataService;
import cn.factorybox.item.utils.DataStatusCount;
import cn.factorybox.item.utils.JudgePcData;
import cn.factorybox.model.entity.*;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author flypig
 * @version 1.0
 * @date 2020-03-04 17:45
 */

@Service
public class DeviceDataServiceImpl implements DeviceDataService {

    private Integer page;

    private Integer size;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private DeviceDataMapper deviceDataMapper;

    @Autowired
    private JudgeValueMapper judgeValueMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public PageResult selectList(Map<String, Object> map) {
        if (map.get("page") != null && map.get("page") != "") {
            this.page = Integer.parseInt((String) map.get("page"));
        } else {
            this.page = 1;
        }
        if (map.get("pagesize") != null && map.get("pagesize") != "") {
            this.size = Integer.parseInt((String) map.get("pagesize"));
        } else {
            this.size = 5;
        }

        PageHelper.startPage(this.page, this.size);

        List<Map<String, Object>> list = this.deviceDataMapper.selectList(map);

        for (Map<String, Object> data : list) {
            data.put("datetime", DateFormatUtil.formatDeviceTime(data.get("datetime")));
        }

        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(list);

        return new PageResult<>(pageInfo.getTotal(), pageInfo.getList());
    }

    /**
     * 获取指定设备号的整点数据
     *
     * @param fSerialNumber
     * @return
     */
    @Override
    public Map<String, Object> getIntegalTime(String fSerialNumber) {
        long startTime = System.currentTimeMillis();   //获取开始时间
        List<DeviceData> list = deviceDataMapper.selectTodayList(fSerialNumber);
        System.out.println("设备号：" + fSerialNumber);
        Map<String, Object> map = new HashMap<>();
        List<Double> tempdata = new ArrayList<>();
        List<Double> humdata = new ArrayList<>();
        List<Double> cotwodata = new ArrayList<>();
        List<Double> tvocdata = new ArrayList<>();
        List<Double> airdata = new ArrayList<>();
        List<Double> pressdata = new ArrayList<>();
        List<Double> pmdata = new ArrayList<>();
        GregorianCalendar gregorianCalendar = new GregorianCalendar();

        try {
            tempdata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fTemperature");
            humdata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fHumidity");
            cotwodata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fCarbonDioxide");
            tvocdata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fTvoc");
            airdata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fExhaust");
            pressdata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fPressure");
            pmdata = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 1, list, "fPm");
        } catch (Exception e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis(); //获取结束时间
        System.out.println("程序运行时间： " + (endTime - startTime) + "ms");
        map.put("id", fSerialNumber);
//        map.put("datetime", new Date()); // 当前时间
        map.put("tempdata", tempdata);
        map.put("humdata", humdata);
        map.put("cotwodata", cotwodata);
        map.put("tvocdata", tvocdata);
        map.put("airdata", airdata);
        map.put("pressdata", pressdata);
        map.put("pmdata", pmdata);

        return map;
    }

    @Override
    public Map<String, Object> getAllDayList(String fSerialNumber) {

        // 获取昨天全部的数据
        List<DeviceData> yesterdayDatas = deviceDataMapper.selectYesterdayList(fSerialNumber);
        // 获取今天的数据
        List<DeviceData> todayDatas = deviceDataMapper.selectTodayList(fSerialNumber);
        Map<String, Object> map = new HashMap<>();
        List<Double> tempdata_today = new ArrayList<>();
        List<Double> tempdata_yestoday = new ArrayList<>();
        List<Double> humdata_today = new ArrayList<>();
        List<Double> humdata_yestoday = new ArrayList<>();
        GregorianCalendar gregorianCalendar = new GregorianCalendar();
        try {
            tempdata_today = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 3, todayDatas, "fTemperature");
            tempdata_yestoday = EchartsUtils.getEchartsData(21, 3, yesterdayDatas, "fTemperature");
            humdata_today = EchartsUtils.getEchartsData(gregorianCalendar.get(Calendar.HOUR_OF_DAY), 3, todayDatas, "fHumidity");
            humdata_yestoday = EchartsUtils.getEchartsData(21, 3, yesterdayDatas, "fHumidity");
        } catch (Exception e) {
            e.printStackTrace();
        }
        map.put("id", fSerialNumber);
        map.put("tempdata_yestoday", tempdata_yestoday);
        map.put("humdata_yestoday", humdata_yestoday);
        map.put("tempdata_today", tempdata_today);
        map.put("humdata_today", humdata_today);
        Map<String, Object> mapdata = new HashMap<>();
        mapdata.put("data", map);

        return mapdata;
    }

    @Override
    public Map<String, Object> getNewData(String fSerialNumber) {

        Map<String, Object> map = new HashMap<>();
        List<JudgeValue> list = new ArrayList<>();
        DeviceData deviceData = deviceDataMapper.getNewData(fSerialNumber);
//        DeviceData deviceData = deviceDataMapper.testGetResult(fSerialNumber);
        if (checkObjFieldIsNotNull(deviceData)) {
            int type = deviceData.getType();  // 环境类别
            System.out.println("设备环境：" + type);
            /**
             * 对数据进行评估
             */
            if (type == 0) {
                list = judgeValueMapper.selectIndoor();
            } else if (type == 1) {
                list = judgeValueMapper.selectExper();
            } else if (type == 2) {
                list = judgeValueMapper.selectOutdoor();
            }

            Map<String, Object> datas = JudgePcData.formatData(deviceData, list);
//        String result = ResultUtils.getResult(type,deviceData,list);
            System.out.println("result:" + deviceData.getResult());

//        map.put("data",deviceData);
            map.put("data", datas);
            return map;
        }
        map.put("data", null);
        return map;
    }

    @Override
    public boolean saveJson(DeviceData deviceData) {
        if (deviceMapper.selectDeviceNum(deviceData.getfSerialNumber()) != 0) {
            int type = deviceMapper.selectType(deviceData.getfSerialNumber());
            List<JudgeValue> list = new ArrayList<>();
            if (type == 0) {
                list = judgeValueMapper.selectIndoor();
            } else if (type == 1) {
                list = judgeValueMapper.selectExper();
            } else if (type == 2) {
                list = judgeValueMapper.selectOutdoor();
            }
            deviceData.setfCreateTime(new Date());
            // 计算数据整体状态
            String result = ResultUtils.getResult(type, deviceData, list);
            deviceData.setResult(result);
            deviceDataMapper.saveJson(deviceData);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean saveRfid(RfidDeviceData deviceData) {
        if (deviceMapper.selectDeviceNum(deviceData.getDeviceID()) != 0) {
            deviceData.setfCreateTime(new Date());
            deviceDataMapper.saveRfid(deviceData);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Map<String, Integer> getWarningList(String fSerialNumber) {

        List<DeviceData> list = deviceDataMapper.selectTodayList(fSerialNumber);
        List<JudgeValue> judges = new ArrayList<>();
        int alldatacount = list.size();
        int type = deviceMapper.selectType(fSerialNumber);
        if (type == 0) {
            judges = judgeValueMapper.selectIndoor();
        } else if (type == 1) {
            judges = judgeValueMapper.selectExper();
        } else if (type == 2) {
            judges = judgeValueMapper.selectOutdoor();
        }
        Map<String, Integer> map = WarningCountUtils.warningCount(list, type, judges);
        map.put("alldatacount", alldatacount);
        return map;
    }

    @Override
    public Map<String, Object> getDifferDatas(String fSerialNumber) {
        String url = "https://tianqiapi.com/api?version=v6&appid=49591446&appsecret=I9Fxai8U&cityid=101280301";
        DeviceData deviceData = deviceDataMapper.getNewData(fSerialNumber);
        List<JudgeValue> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        boolean isExist = checkObjFieldIsNotNull(deviceData);
        int type = deviceMapper.selectType(fSerialNumber);
        if (type == 0) {
            list = judgeValueMapper.selectIndoor();
        } else if (type == 1) {
            list = judgeValueMapper.selectExper();
        } else if (type == 2) {
            list = judgeValueMapper.selectOutdoor();
        }
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
//        params.add("version","v6");
//        params.add("appid","49591446");
//        params.add("appsecret","I9Fxai8U");
        HttpHeaders headers = new HttpHeaders();
//        headers.add("Accept","*/*");
        String response = HttpClient.sendGetRequest(url, params, headers);
        JSONObject json = JSONObject.parseObject(response);
        map.put("id", fSerialNumber);
        // outside
        Map<String, Object> outside = new HashMap<>();
        outside.put("temp", DateFormatUtil.formatDoubleToString1(Double.parseDouble(json.getString("tem"))));
        outside.put("hum", DateFormatUtil.formatDoubleToString1(Double.parseDouble(json.getString("humidity").replace("%", ""))));
        outside.put("press", DateFormatUtil.formatDoubleToString3(Double.parseDouble(json.getString("pressure"))));
        map.put("outside", outside);

        Map<String, Object> inside = new HashMap<>();
        inside.put("temp", isExist ? DateFormatUtil.formatDoubleToString1(deviceData.getfTemperature()) : "");
        inside.put("hum", isExist ? DateFormatUtil.formatDoubleToString1(deviceData.getfHumidity()) : "");
        inside.put("press", isExist ? (DateFormatUtil.formatDoubleToString3(Double.parseDouble(json.getString("pressure")) + deviceData.getfPressure() / 100)) : "");
        map.put("inside", inside);

        Map<String, Object> reduce = new HashMap<>();
        Map<String, Object> temp = new HashMap<>();
        Map<String, Object> hum = new HashMap<>();
        Map<String, Object> press = new HashMap<>();

        temp.put("value", isExist ? Math.abs(DateFormatUtil.formatDouble(deviceData.getfTemperature() - Double.parseDouble(json.getString("tem")))) : "");
        temp.put("style", isExist ? DataStatusCount.tempReduce((Double) temp.get("value")) : "暂无数据比较");
        hum.put("value", isExist ? Math.abs(DateFormatUtil.formatDouble(deviceData.getfHumidity() - Double.parseDouble(json.getString("humidity").replace("%", "")))) : "");
        hum.put("style", isExist ? DataStatusCount.humReduce((Double) hum.get("value")) : "暂无数据比较");
        press.put("value", isExist ? deviceData.getfPressure() : "");
        press.put("style", isExist ? DataStatusCount.pressReduce(((Double) press.get("value")), list.get(2), type) : "暂无数据比较");

        reduce.put("temp", temp);
        reduce.put("hum", hum);
        reduce.put("press", press);
        map.put("reduce", reduce);

        data.put("data", map);
        return map;
    }

    @Override
    public Map<String, Object> getCrestValue(String fSerialNumber) {
        String[] names = {"Temp", "Hum", "Co2", "Exh", "Tvoc", "Press", "Pm"};
        CrestValue crestValue = deviceDataMapper.getCrestValue(fSerialNumber);
        Map<String, Object> map = BeanMapUtils.beanToMap(crestValue);
        List<Map<String, Object>> tableData = new ArrayList<>();
        for (String name : names) {
            Map<String, Object> mapdata = new HashMap<>();
            mapdata.put("type", getDataType(name));
            String max = "max" + name;
//            System.out.println("max:" + max);
            String min = "min" + name;
            mapdata.put("max", map.get(max));
            mapdata.put("min", map.get(min));
            tableData.add(mapdata);
        }
        Map<String, Object> data = new HashMap<>();
        data.put("id", fSerialNumber);
        data.put("tableData", tableData);
        Map<String, Object> maps = new HashMap<>();
        maps.put("data", data);
        return maps;
    }

    @Override
    public Map<String, Object> getDataStatus(String fSerialNumber) {
        Map<String, Object> maps = new HashMap<>();
        List<DeviceData> datas = deviceDataMapper.selectTodayList(fSerialNumber);
        int type = deviceMapper.selectType(fSerialNumber);
        List<JudgeValue> list = new ArrayList<>();
        if (type == 0) {
            list = judgeValueMapper.selectIndoor();
        } else if (type == 1) {
            list = judgeValueMapper.selectExper();
        } else if (type == 2) {
            list = judgeValueMapper.selectOutdoor();
        }
        Map<String, Object> map = DataStatusCount.getStatus(datas, type, list);
        maps.put("data", map);
        return maps;
    }

    @Override
    public Map<String, Object> selectHundredList(String fSerialNumber) {
        List<Map<String, Object>> list = deviceDataMapper.selectHundredList(fSerialNumber);
        for (Map<String, Object> map : list) {
            map.put("datetime", DateFormatUtil.formatDeviceTime(map.get("datetime")));
        }
        Map<String, Object> map = new HashMap<>();
        map.put("data", list);
        return map;
    }

    @Override
    public int deleteData(String id) {
        return deviceDataMapper.deletedata(id);
    }

    @Override
    public Map<String, Object> getWeekDatas(String fSerialNumber, String datetime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> weekMess = new ArrayList<>();
        Map<String, Object> amessCount = new HashMap<>();
        Map<String, Object> params = new HashMap<>();
        int great = 0;
        int normal = 0;
        int info = 0;
        int warn = 0;
        int sum = 0;
        params.put("fSerialNumber", fSerialNumber);
        Date date = sdf.parse(datetime);
        params.put("date", date);
        // 先判断当前日期与传来的date相差的天数，如果大于等于5，就按完整星期处理
        Date nowDate = new Date();
        int num = differentDays(date, nowDate);
        int len = 0;
        if (num >= 5) {
            len = 6;
        } else {
            len = num + 1;
        }
        for (int i = -1; i < len; i++) {
            params.put("num", i);
            List<DeviceData> list = deviceDataMapper.selectWeekDatas(params);
            Map<String, Object> data = new HashMap<>();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DAY_OF_MONTH, i);
            Date weekDate = calendar.getTime();
            String time = sdf.format(weekDate);
            data.put("date", time);
            data.put("week", getWeek(weekDate));
            data.put("warn", DataStatusCount.getWarnCount(list));
            weekMess.add(data);
            great = great + DataStatusCount.getGreatCount(list);
            normal = normal + DataStatusCount.getNormalCount(list);
            info = info + DataStatusCount.getInfoCount(list);
            warn = warn + DataStatusCount.getWarnCount(list);
            sum = sum + list.size();
        }
        amessCount.put("great", great);
        amessCount.put("normal", normal);
        amessCount.put("info", info);
        amessCount.put("warn", warn);
        amessCount.put("sum", sum);

        map.put("weekMess", weekMess);
        map.put("amessCount", amessCount);
        Map<String, Object> data = new HashMap<>();
        data.put("data", map);
        return data;
    }

    @Override
    public Map<String, Object> getMonthDatas(String fSerialNumber, String datetime) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> monthMess = new ArrayList<>();
        Map<String, Object> amessCount = new HashMap<>();
        Map<String, Object> params = new HashMap<>();
        int great = 0;
        int normal = 0;
        int info = 0;
        int warn = 0;
        int sum = 0;
        params.put("fSerialNumber", fSerialNumber);
        Date date = sdf.parse(datetime);
        params.put("date", date);
        // 先判断当前日期与传来的date相差的天数，如果大于等于这个月的天数-1，就按完整月份处理
        Date nowDate = new Date();
        int differDays = differentDays(date, nowDate);
        int monthdays = getMonthDays(date);
        int len = 0;
        if (differDays >= (monthdays - 1)) {
            len = monthdays - 1;
        } else {
            len = differDays;
        }

        for (int i = 0; i <= len; i++) {
            params.put("num", i);
            List<DeviceData> list = deviceDataMapper.selectMonthDatas(params);
            Map<String, Object> data = new HashMap<>();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DAY_OF_MONTH, i);
            Date weekDate = calendar.getTime();
            String time = sdf.format(weekDate);
            data.put("date", time);
            data.put("week", getWeek(weekDate));
            data.put("warn", DataStatusCount.getWarnCount(list));
            monthMess.add(data);
            great = great + DataStatusCount.getGreatCount(list);
            normal = normal + DataStatusCount.getNormalCount(list);
            info = info + DataStatusCount.getInfoCount(list);
            warn = warn + DataStatusCount.getWarnCount(list);
            sum = sum + list.size();
        }
        amessCount.put("great", great);
        amessCount.put("normal", normal);
        amessCount.put("info", info);
        amessCount.put("warn", warn);
        amessCount.put("sum", sum);

        map.put("monthMess", monthMess);
        map.put("amessCount", amessCount);
        Map<String, Object> data = new HashMap<>();
        data.put("data", map);
        return data;
    }

    public static String getDataType(String name) {
        String type = "";
        if (name == "Temp") {
            type = "温度";
        } else if (name == "Hum") {
            type = "湿度";
        } else if (name == "Co2") {
            type = "二氧化碳";
        } else if (name == "Exh") {
            type = "排气次数";
        } else if (name == "Tvoc") {
            type = "气体浓度";
        } else if (name == "Press") {
            type = "大气压差";
        } else if (name == "Pm") {
            type = "PM2.5";
        }
        return type;
    }

    /**
     * 判断两个日期间隔的天数
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDays(Date date1, Date date2) {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    /**
     * 判断日期所在的星期
     */
    public static String getWeek(Date date) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0)
            w = 0;
        return weekDays[w];
    }


    /**
     * 判断日期所在月的天数
     */
    public static int getMonthDays(Date date) {
        int num;
        if (date == null) {
            num = 0;
            return num;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DATE, 1);// 把日期设置为当月第一天
        calendar.roll(Calendar.DATE, -1);// 日期回滚一天，也就是最后一天
        return calendar.get(Calendar.DATE);
    }

    public static boolean checkObjFieldIsNotNull(Object obj) {   // true 不为空  false 为空
        boolean flag = false;
        try {
            for (Field f : obj.getClass().getDeclaredFields()) {
                f.setAccessible(true);
                if (f.get(obj) == null || f.get(obj) == "") {
                } else {
                    flag = true;
                }
            }
        } catch (Exception e) {
            return false;
        }
        return flag;
    }

}
